package com.pacy.pacybaseproject.net;


import com.pacy.pacybaseproject.utils.ConfigUtils;
import com.pacy.pacybaseproject.utils.XUtils;
import com.trello.rxlifecycle2.LifecycleProvider;

import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.Observer;
import io.reactivex.functions.Function;
import me.goldze.mvvmhabit.utils.AppUtil;
import me.goldze.mvvmhabit.utils.RxUtils;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * @author PACY
 * 创建时间 19/1/9 14:36.
 * 邮箱 pengwwe457621023@qq.com
 * 类描述 RetrofitUtil
 */
public class RetrofitUtil {
    private static final int TIME_OUT = 120;//超时时间
    private static ApiService mApiService;

    public static ApiService getApiService() {
        if (mApiService == null) {

//            LoggingInterceptor loggingInterceptor = new LoggingInterceptor.Builder()
//                    .loggable(true)
//                    .setLevel(Level.BODY)
//                    .log(Platform.INFO)
//                    .request("Request") // request的Tag
//                    .response("Response")// Response的Tag
//                    .addHeader("version", BuildConfig.VERSION_NAME)//打印版本
//                    .build();

            Interceptor interceptor = chain -> {
                Request original = chain.request();
                Request request;
                //如果token不为空则添加token到参数列表
                request = original.newBuilder()
                        .addHeader("version", "android_" + AppUtil.getVersionName())
                        .addHeader("Content-Type", "application/json")
                        .method(original.method(), original.body())
                        .build();
                return chain.proceed(request);
            };
            //缓存拦截器
            //缓存时间
            int CACHE_TIMEOUT = 10 * 1024 * 1024;
//            //缓存存放的文件
//            File httpCacheDirectory = new File(mContext.getCacheDir(), "goldze_cache");
//            //缓存对象
//            Cache cache = new Cache(httpCacheDirectory, CACHE_TIMEOUT);
//            okHttpClientBuilder.cache(cache).addInterceptor(new CacheInterceptor(mContext));
            LoggingInterceptor loggingInterceptor = new LoggingInterceptor();

            OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
            //设置请求超时时长
            okHttpClientBuilder
                    .addInterceptor(new TokenInterceptor())
                    .addInterceptor(interceptor)
                    .addInterceptor(loggingInterceptor)
//                    .addInterceptor(new NetInterceptor())
//                    .addInterceptor(getHttpLoggingInterceptor())
                    .readTimeout(TIME_OUT, TimeUnit.SECONDS)
                    .writeTimeout(TIME_OUT, TimeUnit.SECONDS)
                    .retryOnConnectionFailure(true)
                    .connectTimeout(TIME_OUT, TimeUnit.SECONDS);


            Retrofit retrofit = new Retrofit.Builder()
                    //服务器地址
                    .baseUrl(ConfigUtils.BASE_URL)
                    //配置转化库，采用Gson
                    .addConverterFactory(GsonConverterFactory.create())
                    //配置回调库，采用RxJava
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    //设置OKHttpClient为网络客户端
                    .client(okHttpClientBuilder.build()).build();

            mApiService = retrofit.create(ApiService.class);
        }
        return mApiService;
    }


    /**
     * 对observable进行统一转换（用于非文件下载请求）
     *
     * @param observable 被订阅者
     * @param observer   订阅者
     */
    public static void composeToSubscribe(Observable observable, Observer observer, LifecycleProvider lifecycle) {
        observable.compose(getTransformer(lifecycle)).subscribe(observer);
    }

    /**
     * 获取统一转换用的Transformer（用于非文件下载请求）
     */
    public static <T> ObservableTransformer getTransformer(LifecycleProvider lifecycle) {
        return upstream -> {

            //当lifecycleObservable发射事件时，终止操作。
            //统一在请求时切入io线程，回调后进入ui线程
            //加入失败重试机制（延迟3秒开始重试，重试3次）
            return upstream
//                    .retryWhen(new RetryFunction(2, 2))
                    .compose(RxUtils.bindToLifecycle(lifecycle))
                    .compose(RxUtils.schedulersTransformer())
                    .compose(RxUtils.exceptionTransformer());
        };
    }

    //请求失败重试机制
    public static class RetryFunction implements Function<Observable<Throwable>, ObservableSource<?>> {

        private int retryDelaySeconds;//延迟重试的时间
        private int retryCount;//记录当前重试次数
        private int retryCountMax;//最大重试次数

        public RetryFunction(int retryDelaySeconds, int retryCountMax) {
            this.retryDelaySeconds = retryDelaySeconds;
            this.retryCountMax = retryCountMax;
        }

        @Override
        public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
            //方案一：使用zip控制重试次数，重试3次后不再重试（会隐式回调onComplete结束请求，但我需要的是回调onError，所以没采用方案一）
//            return Observable.zip(throwableObservable,Observable.range(1, retryCountMax),new BiFunction<Throwable, Integer, Throwable>() {
//                @Override
//                public Throwable apply(Throwable throwable, Integer integer) throws Exception {
//                    LogUtil.e("ljy",""+integer);
//                    return throwable;
//                }
//            }).flatMap(new Function<Throwable, ObservableSource<?>>() {
//                @Override
//                public ObservableSource<?> apply(Throwable throwable) throws Exception {
//                    if (throwable instanceof UnknownHostException) {
//                        return Observable.error(throwable);
//                    }
//                    return Observable.timer(retryDelaySeconds, TimeUnit.SECONDS);
//                }
//            });


            //方案二：使用全局变量来控制重试次数，重试3次后不再重试，通过代码显式回调onError结束请求
            return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                @Override
                public ObservableSource<?> apply(Throwable throwable) throws Exception {
                    //如果失败的原因是UnknownHostException（DNS解析失败，当前无网络），则没必要重试，直接回调error结束请求即可
                    if (throwable instanceof UnknownHostException) {
                        return Observable.error(throwable);
                    }

                    //没超过最大重试次数的话则进行重试
                    if (++retryCount <= retryCountMax) {
                        //延迟retryDelaySeconds后开始重试
                        return Observable.timer(retryDelaySeconds, TimeUnit.SECONDS);
                    }

                    return Observable.error(throwable);
                }
            });
        }
    }

}
